#include "xthread-mutex.h"
#include "inneral/xthread.h"
#include <stdio.h>
#include <assert.h>

void xthread_mutex_lock(xthread_mutex_t *mutex)
{
    while (1) {
        XPRINT("mutex lock start %d\n", xthread_current->tid);
        if (xthread_spin_trylock(&mutex->wait_lock)) {
            return;
        }
        XPRINT("mutex lock sleep %d\n", xthread_current->tid);
        mutex->waiters++;
        list_add_tail(&xthread_current->list, &mutex->wait_list);
        xthread_block(XTHREAD_BLOCK);
    };
}

void xthread_mutex_unlock(xthread_mutex_t *mutex)
{
    // if not locked, just return
    if (!xthread_spin_is_locked(&mutex->wait_lock)) {
        XPRINT("mutex unlock but not locked %d\n", xthread_current->tid);
        return;
    }
    
    XPRINT("mutex unlock %d\n", xthread_current->tid);
    xthread_spin_unlock(&mutex->wait_lock);
    if (mutex->waiters < 1) {
        return;
    }
    // wake up one water
    xthread_struct_t *thread = list_first_owner_or_null(&mutex->wait_list, xthread_struct_t, list);
    if (thread) {
        XPRINT("mutex unlock wakeup %d\n", thread->tid);
        list_del_init(&thread->list);
        mutex->waiters--;
        // unblock thread untill success
        while (xthread_unblock(thread) == -1);
        // need give othread thread chance to get the lock, so yield now
        xthread_yield();
    }
}